<!-- babylon加载3D模型 -->
<template>
  <div id="babylon-scene">
    <!-- babylonjs容器 - 必须是canvas元素,不能是div之类的其他元素 -->
    <canvas
      v-show="isThree"
      id="renderCanvas"
      ref="renderCanvas"
      touch-action="none"
    ></canvas>
    <ImageScene v-if="!isThree" :pits="Pits" :toiletNo="toiletNo"></ImageScene>
    <!-- 报警gif -->
    <transition name="el-fade-in-linear">
      <img
        v-if="isShowAlarmGIF"
        class="alarm"
        src="../assets/images/model/alarm.gif"
        alt=""
      />
    </transition>
    <!-- 报警提示 -->
    <transition name="el-zoom-in-center">
      <div class="alarmTips" v-if="isShowAlarmTips">
        <div class="tipsTitle">{{ tipsTitle }}</div>
        <div class="tipsContent">{{ tipsContent }}</div>
      </div>
    </transition>
    <!-- 图例 -->
    <ul class="legend" ref="legend">
      <li class="item">
        <span class="fl dot" style="background: #ed97ff"></span>
        <span class="fl txt" style="color: #ed97ff">占用</span>
      </li>
      <li class="item">
        <span class="fl dot" style="background: #54ffd9"></span>
        <span class="fl txt" style="color: #54ffd9">空闲</span>
      </li>
      <li class="item">
        <span class="fl dot" style="background: #fff57b"></span>
        <span class="fl txt" style="color: #fff57b">维修</span>
      </li>
      <el-tooltip content="模拟报警" placement="top" effect="light">
        <li class="item" @click="falseAlarm()" style="cursor: pointer">
          <span class="fl dot" style="background: #ff5a5a"></span>
          <span class="fl txt" style="color: #ff5a5a">SOS</span>
        </li>
      </el-tooltip>
      <li class="item">
        <span class="fl dot" style="background: #717171"></span>
        <span class="fl txt" style="color: #717171">无设备</span>
      </li>
    </ul>
    <!-- 还原、切换视角 -->
    <div class="home-change" ref="homeChange">
      <div class="home" @click="homeEvent()" v-show="isThree">
        <span></span>
        <span>还原</span>
      </div>
      <div class="change" @click="changeEvent()" v-show="isThree">
        <span></span>
        <span>切换视角</span>
      </div>
    </div>
  </div>
</template>

<script>
import ImageScene from "./ImageScene";
import { loadScene, ChangeBestView } from "../scenes/load";
import { showHideSprite, returnpPitNoArr } from "../scenes/execution";
import { data } from "../scenes/data.js"; // 模型的数据源

export default {
  name: "BabylonScene",
  components: {
    ImageScene,
  },
  data() {
    return {
      Pits: [], // 坑位列表
      GL: {
        engine: null,
        scene: null,
        camera: null,
      },
      elseViewIndex: 0, // 切换其他视角
      // 报警提示
      isShowAlarmGIF: false,
      isShowAlarmTips: false,
      tipsTitle: "SOS紧急呼叫",
      tipsContent: "注意！该公厕，发生SOS紧急呼叫！请及时前往处理！",
      voiceContent: null, // 语音播报

      timer: null, // 报警灯和提示
      timer1: null, // 设备报警统计
      timer2: null, // 客流统计
    };
  },
  computed: {},
  props: ["toiletNo", "isThree"],
  watch: {
    toiletNo: function (newVal, oldVal) {
      // console.log(newVal,oldVal);
      // 监听到有数据且发生变化
      if (newVal) {
        if (this.isThree) {
          this.GL.scene && this.GL.scene.dispose();
          this.init();
        } else {
          this.init2D();
        }
      }
    },
    isThree: function (newVal, oldVal) {
      // console.log(newVal,oldVal);
      // 监听到有数据且发生变化
      if (newVal) {
        this.GL.scene && this.GL.scene.dispose();
        this.init();
      } else {
        this.init2D();
      }
    },
  },
  created() {
    // console.log(this.$router);
  },
  destroyed() {
    // console.log("dispose");
    this.timer ? clearTimeout(this.timer) : "";
    this.timer1 ? clearTimeout(this.timer1) : "";
    this.timer2 ? clearTimeout(this.timer2) : "";
    this.GL.scene && this.GL.scene.dispose();
  },
  async mounted() {
    // this.speckText(""); // 先初始化，防止无法播放语音的问题
    this.isThree ? this.init() : this.init2D();
  },
  methods: {
    /**
     * 初始化3D
     */
    init: function () {
      let self = this;
      if (!self.toiletNo) {
        self.$message.warning("未获取到公厕，请联系管理员！");
      }
      let renderCanvas = self.$refs.renderCanvas;
      let homeChange = self.$refs.homeChange;
      let legend = self.$refs.legend;
      if (renderCanvas && self.toiletNo) {
        let config = {
          url: `${self.$common.basePathB}/pit/getPitsState/${self.toiletNo}`,
          method: "get",
          params: {},
          hideLoading: true,
        };
        self
          .axios(config)
          .then(function (res) {
            // console.log(res)
            if (res.data.code == 200) {
              // 参数：画布、公厕编号、坑位数据、是否创建精灵图标、切换视角ref、图例ref
              // loadScene(renderCanvas, self.toiletNo, res.data.list, true, homeChange, legend);
              const { engine, scene, camera } = loadScene(
                renderCanvas,
                self.toiletNo,
                res.data.list,
                true,
                homeChange,
                legend
              );
              self.Pits = res.data.list ? res.data.list : [];
              self.GL = {
                engine: engine,
                scene: scene,
                camera: camera,
              };
              self.useSocket();
            } else {
              self.$message.error(res.data.msg);
            }
          })
          .catch(function (error) {
            console.error(error);
            self.$message.error(error);
          });
      }
    },

    /**
     * 初始化2D
     */
    init2D: function () {
      let self = this;
      if (!self.toiletNo) {
        self.$message.warning("未获取到公厕，请联系管理员！");
      }
      if (self.toiletNo) {
        let config = {
          url: `${self.$common.basePathB}/pit/getPitsState/${self.toiletNo}`,
          method: "get",
          params: {},
          hideLoading: true,
        };
        self
          .axios(config)
          .then(function (res) {
            console.log(res);
            if (res.data.code == 200) {
              console.log(
                "所有坑位编号：",
                returnpPitNoArr(res.data.list ? res.data.list : [], 0)
              );
              console.log(
                "男卫坑位编号：",
                returnpPitNoArr(res.data.list ? res.data.list : [], 1)
              );
              console.log(
                "女卫坑位编号：",
                returnpPitNoArr(res.data.list ? res.data.list : [], 2)
              );
              console.log(
                "第三卫坑位编号：",
                returnpPitNoArr(res.data.list ? res.data.list : [], 3)
              );
              self.Pits = res.data.list ? res.data.list : [];
              self.useSocket();
            } else {
              self.$message.error(res.data.msg);
            }
          })
          .catch(function (error) {
            console.error(error);
            self.$message.error(error);
          });
      }
    },

    useSocket: function () {
      let self = this;

      if (typeof WebSocket == "undefined") {
        self.$message.error(" 您的浏览器不支持 WebSocket");
      } else {
        // console.log(" 您的浏览器支持 WebSocket");

        if (!self.$common.socket) {
          console.log("原来的socket没了，重建一个socket！");
          // 实例化 - 实现化 WebSocket 对象，指定要连接的服务器地址与端口 建立连接
          let wsuri = "";
          window.location.protocol === "http:"
            ? (wsuri =
                "ws://" +
                self.$common.wsuri +
                Math.round(Math.random() * 10000))
            : (wsuri =
                "wss://" +
                self.$common.wsuri +
                Math.round(Math.random() * 10000));

          //创建websoket
          if ("WebSocket" in window) {
            self.$common.socket = new WebSocket(wsuri);
          } else if ("MozWebSocket" in window) {
            self.$common.socket = new MozWebSocket(wsuri);
          } else {
            self.$common.socket = new SockJS(wsuri);
          }
        } else {
          console.log("沿用原来的socket！");
        }

        if (self.$common.socket) {
          // 连接建立成功
          self.$common.socket.onopen = function () {
            console.log("Socket 连接建立成功触发，可以开始通讯了。 ");
          };
          // 接收消息函数，服务器返回的数据在event.data中，接收到的数据是字符串的格式。
          self.$common.socket.onmessage = function (event) {
            console.log(event);
            if (event.data == "连接失败！已经有该窗口连接了！") {
              self.$message.error("连接失败！已经有该窗口连接了！");
            } else {
              // sos报警
              if (event.data.indexOf("AlarmEntity") != -1) {
                console.log("AlarmEntity", self.returnSOSobj(event.data));
                if (
                  (self.$route.name == "ToiletDetail" ||
                    self.$route.name == "ToiletDetailNONAV") &&
                  self.returnSOSobj(event.data)
                ) {
                  self.isShowAlarmGIF = true;
                  self.isShowAlarmTips = true;
                  self.tipsContent =
                    "注意！该公厕坑位编号为：" +
                    self.returnSOSobj(event.data).pitNumber +
                    "，发生SOS紧急呼叫！请及时前往处理！";
                  self.tipsTitle = self.returnSOSobj(event.data).pitNumber;
                  self.speckText(self.tipsContent);

                  // 更新设备报警统计
                  self.timer1 = setTimeout(() => {
                    self.$emit("equipmentAlarmStatistics", self.toiletNo);
                  }, 300); // 延迟100ms，防止后台数据库更新不及时

                  self.timer = setTimeout(() => {
                    // 10s后，关闭报警灯和提示
                    self.isShowAlarmGIF = false;
                    self.isShowAlarmTips = false;
                  }, 10 * 1000);
                }
              }
              // 坑位状态
              if (event.data.indexOf("PitEntity") != -1) {
                console.log("PitEntity", self.returnPitobj(event.data));
                if (
                  (self.$route.name == "ToiletDetail" ||
                    self.$route.name == "ToiletDetailNONAV") &&
                  self.returnPitobj(event.data) &&
                  self.returnPitobj(event.data).length > 0
                ) {
                  // console.log(self.GL.scene)
                  self.Pits = self.returnPitobj(event.data);
                  // 更新坑位状态
                  self.GL.scene && self.isThree
                    ? showHideSprite(
                        self.GL.scene,
                        self.returnPitobj(event.data)
                      )
                    : "";
                  // 更新男女厕的空闲数量
                  // state 坑位状态：0.无人（空闲） 1.有人（占用） 2.故障（维修） 3.未安装（状态3暂时未启用）
                  // type 公厕类型 1.男厕 2.女厕 3.第三卫
                  let male = [];
                  let female = [];
                  self.returnPitobj(event.data).forEach(function (ele) {
                    if (ele.type == 1 && ele.state == 0) {
                      male.push(ele);
                    }
                    if (ele.type == 2 && ele.state == 0) {
                      female.push(ele);
                    }
                  });
                  self.$emit("updataKxTotal", {
                    male: male.length,
                    female: female.length,
                  });
                  // 更新客流统计
                  // self.timer2 = setTimeout(() => {
                  //   self.$emit("queryFlow", self.toiletNo, false);
                  // }, 100); // 延迟100ms，防止后台数据库更新不及时
                }
              }
              // 客流
              if (event.data.indexOf("PassengerFlow") != -1) {
                console.log("PassengerFlow", self.returnFlowobj(event.data));
                if (
                  (self.$route.name == "ToiletDetail" ||
                    self.$route.name == "ToiletDetailNONAV") &&
                  self.returnFlowobj(event.data) &&
                  self.returnFlowobj(event.data).length > 0
                ) {
                  // 更新客流统计
                  // self.$emit(
                  //   "queryFlow",
                  //   self.toiletNo,
                  //   true,
                  //   self.returnFlowobj(event.data)
                  // );
                }
              }
            }
          };
          // 连接关闭事件
          self.$common.socket.onclose = function () {
            console.log("Socket 连接已关闭。");
            // self.$common.socket = null;
            // self.$message.error("Socket 连接已关闭。");
          };
          // 连接失败事件
          self.$common.socket.onerror = function () {
            console.log("Socket 连接失败，发生了错误！");
            // self.reconnectWebSoket();
            self.useSocket();
            // 此时可以尝试刷新页面
          };
        }
      }
    },

    // 模拟报警，10s后恢复原状！
    falseAlarm: function () {
      let self = this;
      self.isShowAlarmGIF = true;
      self.isShowAlarmTips = true;
      self.speckText(self.tipsContent);
      // 更新坑位状态
      let pits_alarm = JSON.parse(JSON.stringify(self.Pits));
      let pits_normal = JSON.parse(JSON.stringify(self.Pits));
      pits_alarm.forEach(function (element) {
        // 设置第三卫生间为报警状态
        // if (element.pitNo == self.threeInfo.pitNo) {
        element.alarmState = 2;
        // }
      });
      pits_normal.forEach(function (element) {
        // 设置第三卫生间为正常状态
        // if (element.pitNo == self.threeInfo.pitNo) {
        element.alarmState = 1;
        // }
      });
      self.GL.scene && self.isThree
        ? showHideSprite(self.GL.scene, pits_alarm)
        : "";

      setTimeout(() => {
        self.isShowAlarmGIF = false;
        self.isShowAlarmTips = false;
        // 更新坑位状态
        self.GL.scene && self.isThree
          ? showHideSprite(self.GL.scene, pits_normal)
          : "";
      }, 10 * 1000);
    },

    // 返回sos的报警信息
    returnSOSobj: function (eventData) {
      // 'AlarmEntity{toiletId=1, pitNumber=PIT-33-01, count=1, updateTime=2022-04-08 09:23:39}'
      let self = this;
      let sosAlarm = eventData.split("AlarmEntity{")[1].split("}")[0];
      let sosAlarmArr = null;
      if (sosAlarm) {
        sosAlarmArr = sosAlarm.split(",");
      }
      let sosObj = {
        state: 1, // 未处理的报警
        ws: true, // 由ws推送
      };
      if (sosAlarmArr) {
        sosAlarmArr.forEach(function (sos) {
          // 去除字符串内所有的空格：str = str.replace(/\s*/g,"");
          // 去除字符串内两头的空格：str = str.replace(/^\s*|\s*$/g,"");
          // 去除字符串内左侧的空格：str = str.replace(/^\s*/,"");
          // 去除字符串内右侧的空格：str = str.replace(/(\s*$)/g,"");
          sosObj[sos.split("=")[0].replace(/^\s*|\s*$/g, "")] =
            sos.split("=")[1];
        });
      }

      // 根据self.toiletNo，筛选出该厕所的报警信息
      if (self.toiletNo == sosObj.toiletId) {
        return sosObj;
      } else {
        return null;
      }
    },

    // 返回坑位列表的状态信息
    returnPitobj: function (eventData) {
      // [PitEntity(id=1, toiletId=1, number=PIT-33-001, state=1, type=1, alarmState=1, createTime=Thu Dec 09 13:49:28 CST 2021, updateTime=Tue Apr 12 10:16:47 CST 2022), PitEntity(id=2, toiletId=1, number=PIT-33-002, state=2, type=1, alarmState=1, createTime=Thu Dec 09 13:49:28 CST 2021, updateTime=Tue Apr 12 10:39:14 CST 2022), PitEntity(id=3, toiletId=1, number=PIT-33-003, state=3, type=2, alarmState=2, createTime=Thu Dec 09 13:49:28 CST 2021, updateTime=Tue Apr 12 10:47:02 CST 2022)]
      let self = this;
      let pitArr = eventData
        .split("[")[1]
        .split("]")[0]
        .split("PitEntity");
      let pitInfos = [];
      if (pitArr && pitArr.length > 0) {
        pitArr.forEach(function (pitInfo) {
          if (pitInfo && pitInfo.indexOf("alarmState=") != -1 && pitInfo.indexOf("state=") != -1) {
            let pitObj = {};
            let pitInfoArr = pitInfo.split("(")[1].split(")")[0].split(",");
            if (pitInfoArr && pitInfoArr.length > 0) {
              pitInfoArr.forEach(function (pit) {
                // 去除字符串内所有的空格：str = str.replace(/\s*/g,"");
                // 去除字符串内两头的空格：str = str.replace(/^\s*|\s*$/g,"");
                // 去除字符串内左侧的空格：str = str.replace(/^\s*/,"");
                // 去除字符串内右侧的空格：str = str.replace(/(\s*$)/g,"");
                pitObj[pit.split("=")[0].replace(/^\s*|\s*$/g, "")] =
                  pit.split("=")[1];
              });
            }
            Object.keys(pitObj).length > 0 ? pitInfos.push(pitObj) : "";
          }
        });
      }

      // 根据self.toiletNo，筛选出该厕所的坑位信息
      if (pitInfos.length > 0 && self.toiletNo == pitInfos[0].toiletId) {
        return pitInfos;
      } else {
        return null;
      }
    },

    // 返回客流统计
    returnFlowobj: function (eventData) {
      // PassengerFlow{toiletId=1, nowFlowCnt=1, totalFlowCnt=22, type=1}
      let self = this;
      let pitArr = eventData.split("PassengerFlow");
      let pitInfos = [];
      if (pitArr && pitArr.length > 0) {
        pitArr.forEach(function (pitInfo) {
          if (
            pitInfo &&
            pitInfo.indexOf("nowFlowCnt=") != -1 &&
            pitInfo.indexOf("totalFlowCnt=") != -1
          ) {
            let pitObj = {};
            let pitInfoArr = pitInfo.split("{")[1].split("}")[0].split(",");
            if (pitInfoArr && pitInfoArr.length > 0) {
              pitInfoArr.forEach(function (pit) {
                // 去除字符串内所有的空格：str = str.replace(/\s*/g,"");
                // 去除字符串内两头的空格：str = str.replace(/^\s*|\s*$/g,"");
                // 去除字符串内左侧的空格：str = str.replace(/^\s*/,"");
                // 去除字符串内右侧的空格：str = str.replace(/(\s*$)/g,"");
                pitObj[pit.split("=")[0].replace(/^\s*|\s*$/g, "")] =
                  pit.split("=")[1];
              });
            }
            Object.keys(pitObj).length > 0 ? pitInfos.push(pitObj) : "";
          }
        });
      }
      // 根据self.toiletNo，筛选出该厕所的客流统计
      if (pitInfos.length > 0 && self.toiletNo == pitInfos[0].toiletId) {
        return pitInfos;
      } else {
        return null;
      }
    },

    /**
     * 语音播报
     */
    speckText: function (text) {
      let self = this;

      if (window.speechSynthesis) {
        let synth = window.speechSynthesis;
        let msg = new SpeechSynthesisUtterance();
        msg.text = text; // 文字内容
        msg.lang = "zh-CN"; // 使用的语言:中文
        msg.volume = 100; // 声音音量：1
        msg.rate = 1; // 语速：1，范围是0.1到10
        msg.pitch = 1; // 音高：1，范围从0（最小）到2（最大）
        msg.voice = self.getWindowVoice(); // 使用本地服务合成语音(若是获取不到 请异步获取, 加一个setTimeout)

        // 存在问题 : google chrome 播放语音可能会卡住 所以无声音
        // 解决办法 : 在播放语音之前先 调用一下cancel方法
        synth.cancel(msg);

        // 播放
        synth.speak(msg);
      }
      // 暂停
      // window.speechSynthesis.pause(msg);
      // 继续
      // window.speechSynthesis.resume(msg);
    },
    // 存在问题：在google chrome 89版本之后 默认使用的线上服务来合成语音 所以在国内可能会没有声音
    // 解决办法：通过getVoices 获取 localService为true 的字段 （localService = true 表示 使用本地合成服务）
    // 获取浏览器中语音 (中文 + 本地服务)
    getWindowVoice: function () {
      return window.speechSynthesis
        .getVoices()
        .find((item) => item.localService && item.lang === "zh-CN");
    },

    /**
     * 还原
     * elseView 0
     */
    homeEvent: function () {
      let self = this;
      if (self.toiletNo) {
        ChangeBestView(
          self.GL.scene,
          self.GL.camera,
          data[self.toiletNo].position,
          data[self.toiletNo].target
        );
        self.elseViewIndex = 0;
      }
    },

    /**
     * 切换视角
     * elseView 0,1,2,3
     */
    changeEvent: function () {
      let self = this;
      if (self.toiletNo) {
        let elseView = data[self.toiletNo].elseView;
        self.elseViewIndex++;
        if (self.elseViewIndex > 3) {
          self.elseViewIndex = 0;
        }
        let result = elseView[self.elseViewIndex];

        ChangeBestView(
          self.GL.scene,
          self.GL.camera,
          result.position,
          result.target
        );
      }
    },
  },
};
</script>

<style lang="less">
#babylon-scene {
  width: 100%;
  height: 100%;
  canvas {
    width: 100%;
    height: 100%;
    outline: none;
    background: url(../assets/images/model/canvas.png) no-repeat center center;
    background-size: 100% 100%;
  }

  .alarm {
    position: absolute;
    top: 0rem;
    left: 0rem;
    width: 1.25rem !important;
    height: auto !important;
  }

  .alarmTips {
    position: absolute;
    bottom: 0.77rem;
    left: calc((100% - 4.2rem) / 2);
    height: 1.2rem;
    width: 4.2rem;
    background: url(../assets/images/model/alarmBG.png) no-repeat center center;
    background-size: 100% 100%;
  }

  .alarmTips .tipsTitle {
    width: 100%;
    text-align: center;
    height: 0.32rem;
    font-size: 0.3rem;
    font-family: PingFangSC-Semibold, PingFang SC;
    font-weight: 900;
    color: #ff3939;
    line-height: 0.32rem;
    margin: 0.04rem 0 0.05rem 0;
  }

  .alarmTips .tipsContent {
    width: 3.66rem;
    /* height: 0.4rem; */
    font-size: 0.18rem;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 600;
    color: #ff3939;
    line-height: 0.32rem;
    margin: 0 auto;
  }

  .home-change {
    position: absolute;
    top: 0.09rem;
    width: 1.55rem;
    right: 0.09rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 0.2rem;
  }

  .home-change .home {
    display: flex;
    align-items: center;
    justify-content: space-between;
    // width: 0.45rem;
    height: 0.2rem;
    cursor: pointer;
  }

  .home-change .home:hover span:nth-child(2) {
    color: #77e9ff;
  }

  .home-change .home span:nth-child(1) {
    background: url(../assets/images/model/home.png) no-repeat center center;
    background-size: 100% 100%;
    width: 0.14rem;
    height: 0.14rem;
  }

  .home-change .home span:nth-child(2) {
    width: auto;
    height: 0.2rem;
    font-size: 0.14rem;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: rgba(255, 255, 255, 1);
    line-height: 0.2rem;
  }

  .home-change .change {
    display: flex;
    align-items: center;
    justify-content: space-between;
    // width: 0.75rem;
    height: 0.2rem;
    cursor: pointer;
  }

  .home-change .change:hover span:nth-child(2) {
    color: #77e9ff;
  }

  .home-change .change span:nth-child(1) {
    background: url(../assets/images/model/change.png) no-repeat center center;
    background-size: 100% 100%;
    width: 0.14rem;
    height: 0.14rem;
  }

  .home-change .change span:nth-child(2) {
    width: auto;
    height: 0.2rem;
    font-size: 0.14rem;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: rgba(255, 255, 255, 1);
    line-height: 0.2rem;
  }

  .legend {
    position: absolute;
    bottom: 0.25rem;
    width: 100%;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: space-around;
    height: 0.38rem;
  }

  .legend .item {
    height: 0.38rem;
  }

  .legend .item .dot {
    width: 0.23rem;
    height: 0.23rem;
    border-radius: 50%;
    margin-top: 0.08rem;
  }

  .legend .item .txt {
    height: 0.38rem;
    font-size: 0.27rem;
    font-family: PingFangSC-Semibold, PingFang SC;
    font-weight: 600;
    line-height: 0.34rem;
    margin-left: 0.07rem;
  }
}
</style>
